#include "pbm.h"

namespace pbm {

  const char *hex_strings[] =
  {
    "0",
    "1","2","3","4","5","6","7","8","9","10",
    "11","12","13","14","15","16","17","18","19","20",
    "21","22","23","24","25","26","27","28","29","30",
    "31","32","33","34","35","36","37","38","39","40",
    "41","42","43","44","45","46","47","48","49","50",
    "51","52","53","54","55","56","57","58","59","60",
    "61","62","63","64","65","66","67","68","69","70",
    "71","72","73","74","75","76","77","78","79","80",
    "81","82","83","84","85","86","87","88","89","90",
    "91","92","93","94","95","96","97","98","99","100",
    "101","102","103","104","105","106","107","108","109","110",
    "111","112","113","114","115","116","117","118","119","120",
    "121","122","123","124","125","126","127","128","129","130",
    "131","132","133","134","135","136","137","138","139","140",
    "141","142","143","144","145","146","147","148","149","150",
    "151","152","153","154","155","156","157","158","159","160",
    "161","162","163","164","165","166","167","168","169","170",
    "171","172","173","174","175","176","177","178","179","180",
    "181","182","183","184","185","186","187","188","189","190",
    "191","192","193","194","195","196","197","198","199","200",
    "201","202","203","204","205","206","207","208","209","210",
    "211","212","213","214","215","216","217","218","219","220",
    "221","222","223","224","225","226","227","228","229","230",
    "231","232","233","234","235","236","237","238","239","240",
    "241","242","243","244","245","246","247","248","249","250",
    "251","252","253","254","255"
  };

  void to_pbm1(const array2d<bool> &arr, string &output) {
    const unsigned int rows = arr.get_row_count();
    const unsigned int columns = arr.get_column_count();

    output.reserve(rows * columns + rows * strlen("\n"));
    output = "P1\n%1 %2\n";
    str::format(output, arg<unsigned int>(columns, rows));

    for (unsigned int i = 0; i < rows; ++i) {
      for (unsigned int j = 0; j < columns; ++j)
        output += (arr(i, j) + '0');

      output += '\n';
    }

    if (output.empty() == false && *output.rbegin() == '\n')
      output.resize(output.length() - 1); // removes the last "\n"
  }

  void to_pbm1_file(const array2d<bool> &arr, const string &file_name) {
    string s;
    to_pbm1(arr, s);
    binary_write(file_name, s);
  }

  void to_pbm3(const array2d<unsigned int> &arr, string &output) {
    const unsigned int rows = arr.get_row_count();
    const unsigned int columns = arr.get_column_count();

    output.reserve(rows * columns + rows * strlen("\n"));
    output = "P3\n%1 %2\n255\n";
    str::format(output, arg<unsigned int>(columns, rows));

    for (unsigned int i = 0; i < rows; ++i) {
      for (unsigned int j = 0; j < columns; ++j) {
        const unsigned int &x = arr(i, j);

        output += hex_strings[x & 0xff];
        output += ' ';
        output += hex_strings[(x & 0xff00) >> 8];
        output += ' ';
        output += hex_strings[(x & 0xff0000) >> 16];
        output += '\n';
      }
    }

    if (output.empty() == false && *output.rbegin() == '\n')
      output.resize(output.length() - 1); // removes the last "\n"
  }

  void to_pbm3_file(const array2d<unsigned int> &arr, const string &file_name) {
    string s;
    to_pbm3(arr, s);
    binary_write(file_name, s);
  }

} // namespace pbm
